use super::super::{
    ray::Ray,
    vec::*,
};
use super::hittable::HitRecord;

pub trait Material {
    fn scatter(&self, ray_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered:&mut Ray) -> bool;
}


// Lambertian
pub struct Lambertian {
    albedo: Color,
}


impl Lambertian {
    pub fn new(c: Color) -> Self {
        Self{albedo: c}
    }
}

impl Material for Lambertian {
    fn scatter(&self, ray_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered:&mut Ray) -> bool {
        let mut scatter_dir = rec.get_normal() +  random_unit_vector();
        
        if scatter_dir.near_zero() {
            scatter_dir = rec.get_normal();
        }
        
        *scattered = Ray::new(rec.get_point(), scatter_dir );
        *attenuation = self.albedo.clone();

        true
    }
}

/// Metal
pub struct Metal {
    albedo: Color,
    fuzz: f32,
}

impl Metal {
    pub fn new(c: Color, fuzz: f32) -> Self {
        Self{albedo: c, fuzz}
    }
}

impl Material for Metal {
    fn scatter(&self, ray_in: &Ray, rec: &HitRecord, attenuation: &mut Color, scattered:&mut Ray) -> bool {
        let reflected = reflect(&ray_in.direction().unit_vector(), &rec.get_normal());
        
        *scattered = Ray::new(rec.get_point(), reflected + self.fuzz * random_in_unit_sphere() );
        *attenuation = self.albedo.clone();
        return scattered.direction().dot(&rec.get_normal()) > 0.0;

    }
}

